package com.harmony.pilot.agent.tools;

import com.harmony.pilot.agent.model.*;
import com.harmony.pilot.agent.service.LLMServiceClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * 代码审查和最佳实践提示工具
 * 分析用户当前代码，提供OpenHarmony开发最佳实践建议
 */
@Component
@Slf4j
public class CodeReviewTool implements AgentTool {
    
    private final LLMServiceClient llmServiceClient;
    private final RestTemplate restTemplate;
    
    @Value("${services.analysis.url:http://localhost:8083}")
    private String analysisServiceUrl;
    
    // OpenHarmony最佳实践检查项
    private static final List<String> BEST_PRACTICES = Arrays.asList(
        "命名规范：使用驼峰命名法，类名首字母大写，函数名首字母小写",
        "内存管理：使用智能指针（shared_ptr、unique_ptr）避免内存泄漏",
        "错误处理：使用返回值或异常处理错误，避免忽略错误",
        "线程安全：多线程环境下注意同步和锁的使用",
        "性能优化：避免不必要的拷贝，使用移动语义",
        "编码规范：遵循OpenHarmony C++编码规范",
        "头文件：包含必要的头文件，避免循环依赖",
        "文档注释：为公共API添加详细注释",
        "单元测试：确保代码有对应的单元测试",
        "异常安全：使用RAII原则确保资源正确释放"
    );
    
    public CodeReviewTool(LLMServiceClient llmServiceClient, 
                         @Autowired(required = false) RestTemplate restTemplate) {
        this.llmServiceClient = llmServiceClient;
        this.restTemplate = restTemplate != null ? restTemplate : new RestTemplate();
    }
    
    @Override
    public String getName() {
        return "code_review";
    }
    
    @Override
    public String getDescription() {
        return "代码审查和最佳实践提示，分析代码并提供OpenHarmony开发最佳实践建议";
    }
    
    @Override
    public String getParametersSchema() {
        return """
            {
              "type": "object",
              "properties": {
                "filePath": {
                  "type": "string",
                  "description": "要审查的文件路径"
                },
                "code": {
                  "type": "string",
                  "description": "代码内容（可选，如果不提供则从文件读取）"
                },
                "focus": {
                  "type": "string",
                  "description": "审查重点（performance, security, style, best-practices）"
                }
              }
            }
            """;
    }
    
    @Override
    public boolean canHandle(Intent intent, ConversationContext context) {
        return intent.getType() == Intent.IntentType.CODE_REVIEW ||
               intent.getType() == Intent.IntentType.CODE_ANALYSIS;
    }
    
    @Override
    public double getRelevanceScore(Intent intent, ConversationContext context) {
        if (intent.getType() == Intent.IntentType.CODE_REVIEW) {
            return 0.95;
        }
        if (intent.getType() == Intent.IntentType.CODE_ANALYSIS) {
            return 0.90;
        }
        return 0.0;
    }
    
    @Override
    public ToolResult execute(ToolRequest request) {
        Map<String, Object> params = request.getParameters();
        if (params == null) {
            params = new HashMap<>();
        }
        
        String filePath = (String) params.get("filePath");
        String code = (String) params.get("code");
        String focus = (String) params.getOrDefault("focus", "best-practices");
        
        // 如果没有提供文件路径，尝试从上下文获取
        if (filePath == null || filePath.isEmpty()) {
            filePath = request.getContext().getCurrentFile();
        }
        
        try {
            // 1. 读取代码（如果未提供）
            if (code == null || code.isEmpty()) {
                if (filePath == null || filePath.isEmpty()) {
                    return ToolResult.error("未指定要审查的文件路径或代码内容");
                }
                code = readCodeFromFile(filePath, request.getContext().getProjectRoot());
            }
            
            // 2. 执行代码分析
            CodeAnalysisResult analysisResult = analyzeCode(code, filePath);
            
            // 3. 生成最佳实践建议
            List<BestPracticeSuggestion> suggestions = generateBestPracticeSuggestions(
                code, filePath, analysisResult, focus
            );
            
            // 4. 构建响应数据
            Map<String, Object> data = new HashMap<>();
            data.put("filePath", filePath);
            data.put("analysis", analysisResult);
            data.put("suggestions", suggestions);
            data.put("score", calculateCodeScore(analysisResult, suggestions));
            
            StringBuilder message = new StringBuilder();
            message.append("代码审查完成！\n\n");
            message.append("代码评分：").append(data.get("score")).append("/100\n\n");
            message.append("发现 ").append(suggestions.size()).append(" 条最佳实践建议\n\n");
            
            if (!suggestions.isEmpty()) {
                message.append("主要建议：\n");
                for (int i = 0; i < Math.min(3, suggestions.size()); i++) {
                    BestPracticeSuggestion suggestion = suggestions.get(i);
                    message.append(i + 1).append(". ")
                           .append(suggestion.getTitle()).append("\n");
                }
            }
            
            return ToolResult.success(message.toString(), data);
            
        } catch (Exception e) {
            log.error("Failed to review code", e);
            return ToolResult.error("代码审查失败: " + e.getMessage());
        }
    }
    
    private String readCodeFromFile(String filePath, String projectRoot) throws Exception {
        String fullPath = filePath;
        if (projectRoot != null && !projectRoot.isEmpty()) {
            fullPath = Paths.get(projectRoot, filePath).toString();
        }
        return Files.readString(Paths.get(fullPath));
    }
    
    private CodeAnalysisResult analyzeCode(String code, String filePath) {
        CodeAnalysisResult result = new CodeAnalysisResult();
        
        // 基础分析
        result.setLinesOfCode(code.split("\n").length);
        result.setHasMainFunction(code.contains("int main(") || code.contains("void main("));
        result.setHasClass(code.contains("class "));
        result.setHasNamespace(code.contains("namespace "));
        
        // 调用代码分析服务（如果可用）
        List<CodeIssue> issues = new ArrayList<>();
        
        try {
            if (restTemplate != null && analysisServiceUrl != null) {
                com.harmony.pilot.common.dto.CodeContext codeContext = 
                    new com.harmony.pilot.common.dto.CodeContext();
                codeContext.setFilePath(filePath);
                codeContext.setCode(code);
                
                com.harmony.pilot.common.dto.AnalysisRequest analysisRequest = 
                    com.harmony.pilot.common.dto.AnalysisRequest.builder()
                        .context(codeContext)
                        .build();
                
                com.harmony.pilot.common.dto.RestResult<com.harmony.pilot.common.dto.AnalysisResult> 
                    analysisResult = restTemplate.postForObject(
                        analysisServiceUrl + "/analysis/analyze",
                        analysisRequest,
                        com.harmony.pilot.common.dto.RestResult.class
                    );
                
                if (analysisResult != null && analysisResult.isSuccess() && 
                    analysisResult.getData() != null) {
                    // 转换分析结果为CodeIssue
                    com.harmony.pilot.common.dto.AnalysisResult data = analysisResult.getData();
                    if (data.getIssues() != null) {
                        for (com.harmony.pilot.common.dto.AnalysisResult.Issue issue : data.getIssues()) {
                            issues.add(new CodeIssue(
                                issue.getType(),
                                issue.getSeverity(),
                                issue.getMessage(),
                                issue.getFixSuggestion()
                            ));
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("Failed to call analysis service, using rule-based analysis", e);
        }
        
        // 如果分析服务不可用，使用规则分析
        if (issues.isEmpty()) {
            issues.addAll(performRuleBasedAnalysis(code));
        }
        
        result.setIssues(issues);
        return result;
    }
    
    private List<CodeIssue> performRuleBasedAnalysis(String code) {
        List<CodeIssue> issues = new ArrayList<>();
        
        // 检查内存管理
        if (code.contains("new ") && !code.contains("shared_ptr") && !code.contains("unique_ptr")) {
            issues.add(new CodeIssue(
                "memory_management",
                "warning",
                "使用了原始指针 new，建议使用智能指针（shared_ptr或unique_ptr）",
                "OpenHarmony推荐使用智能指针进行内存管理，避免内存泄漏"
            ));
        }
        
        // 检查错误处理
        if (code.contains("return -1") || code.contains("return NULL")) {
            issues.add(new CodeIssue(
                "error_handling",
                "info",
                "使用了简单的错误返回，建议使用更明确的错误处理机制",
                "考虑使用异常处理或错误码枚举"
            ));
        }
        
        // 检查线程安全
        if (code.contains("mutex") || code.contains("lock")) {
            issues.add(new CodeIssue(
                "thread_safety",
                "info",
                "检测到线程同步代码，请确保正确使用锁",
                "注意避免死锁，考虑使用RAII锁管理"
            ));
        }
        
        // 检查头文件包含
        if (code.contains("#include")) {
            long includeCount = code.lines().filter(line -> line.trim().startsWith("#include")).count();
            if (includeCount > 20) {
                issues.add(new CodeIssue(
                    "header_includes",
                    "warning",
                    "头文件包含过多（" + includeCount + "个），建议检查是否有冗余",
                    "过多的头文件包含会增加编译时间和依赖"
                ));
            }
        }
        
        // 检查注释
        long commentLines = code.lines()
            .filter(line -> line.trim().startsWith("//") || line.trim().startsWith("/*"))
            .count();
        double commentRatio = (double) commentLines / code.split("\n").length;
        if (commentRatio < 0.1 && commentLines < 10) {
            issues.add(new CodeIssue(
                "documentation",
                "info",
                "代码注释较少，建议为公共API添加详细注释",
                "OpenHarmony要求为公共接口提供完整的文档注释"
            ));
        }
        
        // 检查OpenHarmony特定规范
        if (code.contains("using namespace std")) {
            issues.add(new CodeIssue(
                "coding_style",
                "warning",
                "使用了using namespace std，OpenHarmony建议使用完整命名空间",
                "避免使用using namespace，使用std::前缀"
            ));
        }
        
        return issues;
    }
    
    private List<BestPracticeSuggestion> generateBestPracticeSuggestions(
            String code, String filePath, CodeAnalysisResult analysis, String focus) {
        
        List<BestPracticeSuggestion> suggestions = new ArrayList<>();
        
        // 使用LLM生成针对性建议
        try {
            StringBuilder prompt = new StringBuilder();
            prompt.append("请分析以下C++代码，提供OpenHarmony开发最佳实践建议。\n\n");
            prompt.append("文件路径：").append(filePath != null ? filePath : "未知").append("\n\n");
            prompt.append("代码内容：\n```cpp\n").append(code.substring(0, Math.min(2000, code.length()))).append("\n```\n\n");
            
            if ("performance".equals(focus)) {
                prompt.append("重点关注：性能优化建议\n");
            } else if ("security".equals(focus)) {
                prompt.append("重点关注：安全性建议\n");
            } else if ("style".equals(focus)) {
                prompt.append("重点关注：代码风格建议\n");
            } else {
                prompt.append("重点关注：OpenHarmony最佳实践\n");
            }
            
            prompt.append("\n请提供3-5条具体的改进建议，每条建议包括：\n");
            prompt.append("1. 标题（简短描述问题）\n");
            prompt.append("2. 问题描述\n");
            prompt.append("3. 改进建议\n");
            prompt.append("4. 代码示例（如果适用）\n");
            prompt.append("5. 优先级（high/medium/low）\n");
            
            prompt.append("\n请以JSON格式返回，格式如下：\n");
            prompt.append("[\n");
            prompt.append("  {\n");
            prompt.append("    \"title\": \"建议标题\",\n");
            prompt.append("    \"description\": \"问题描述\",\n");
            prompt.append("    \"suggestion\": \"改进建议\",\n");
            prompt.append("    \"example\": \"代码示例\",\n");
            prompt.append("    \"priority\": \"high|medium|low\",\n");
            prompt.append("    \"category\": \"内存管理|性能|安全|风格\"\n");
            prompt.append("  }\n");
            prompt.append("]\n");
            
            String llmResponse = llmServiceClient.generate(prompt.toString());
            
            // 解析LLM响应（简化处理，实际应该使用JSON解析）
            suggestions.addAll(parseLLMSuggestions(llmResponse));
            
        } catch (Exception e) {
            log.error("Failed to generate suggestions with LLM", e);
        }
        
        // 基于规则生成补充建议
        suggestions.addAll(generateRuleBasedSuggestions(code, analysis));
        
        // 按优先级排序
        suggestions.sort((a, b) -> {
            int priorityOrder = Map.of("high", 0, "medium", 1, "low", 2);
            return priorityOrder.getOrDefault(a.getPriority(), 3)
                .compareTo(priorityOrder.getOrDefault(b.getPriority(), 3));
        });
        
        return suggestions;
    }
    
    private List<BestPracticeSuggestion> parseLLMSuggestions(String llmResponse) {
        List<BestPracticeSuggestion> suggestions = new ArrayList<>();
        
        // 简化处理：如果LLM返回的是JSON，应该使用JSON解析器
        // 这里先返回一些默认建议
        if (llmResponse != null && !llmResponse.trim().isEmpty()) {
            // TODO: 使用Jackson或Gson解析JSON
            // 临时返回示例建议
            suggestions.add(new BestPracticeSuggestion(
                "遵循OpenHarmony编码规范",
                "代码应遵循OpenHarmony C++编码规范",
                "参考OpenHarmony编码规范文档，确保代码风格一致",
                "",
                "medium",
                "风格"
            ));
        }
        
        return suggestions;
    }
    
    private List<BestPracticeSuggestion> generateRuleBasedSuggestions(
            String code, CodeAnalysisResult analysis) {
        
        List<BestPracticeSuggestion> suggestions = new ArrayList<>();
        
        // 基于分析结果生成建议
        for (CodeIssue issue : analysis.getIssues()) {
            if ("memory_management".equals(issue.getType())) {
                suggestions.add(new BestPracticeSuggestion(
                    "使用智能指针管理内存",
                    issue.getMessage(),
                    "将原始指针改为shared_ptr或unique_ptr，确保资源自动释放",
                    "// 不推荐：\nint* ptr = new int(10);\n// 推荐：\nstd::unique_ptr<int> ptr = std::make_unique<int>(10);",
                    "high",
                    "内存管理"
                ));
            } else if ("error_handling".equals(issue.getType())) {
                suggestions.add(new BestPracticeSuggestion(
                    "改进错误处理机制",
                    issue.getMessage(),
                    "使用异常处理或明确的错误码枚举，提高代码可读性和可维护性",
                    "",
                    "medium",
                    "错误处理"
                ));
            } else if ("documentation".equals(issue.getType())) {
                suggestions.add(new BestPracticeSuggestion(
                    "添加代码注释",
                    issue.getMessage(),
                    "为公共API和复杂逻辑添加详细注释，遵循Doxygen格式",
                    "/**\n * @brief 函数功能描述\n * @param param 参数说明\n * @return 返回值说明\n */",
                    "low",
                    "文档"
                ));
            }
        }
        
        // OpenHarmony特定建议
        if (code.contains("namespace") && !code.contains("namespace OHOS")) {
            suggestions.add(new BestPracticeSuggestion(
                "使用OpenHarmony命名空间",
                "建议使用OHOS命名空间",
                "OpenHarmony项目推荐使用OHOS命名空间，保持代码一致性",
                "namespace OHOS {\n    // 代码\n}",
                "low",
                "风格"
            ));
        }
        
        return suggestions;
    }
    
    private int calculateCodeScore(CodeAnalysisResult analysis, 
                                   List<BestPracticeSuggestion> suggestions) {
        int score = 100;
        
        // 根据问题数量扣分
        for (CodeIssue issue : analysis.getIssues()) {
            if ("error".equals(issue.getSeverity())) {
                score -= 10;
            } else if ("warning".equals(issue.getSeverity())) {
                score -= 5;
            } else {
                score -= 2;
            }
        }
        
        // 根据建议数量扣分
        long highPriorityCount = suggestions.stream()
            .filter(s -> "high".equals(s.getPriority()))
            .count();
        score -= (int) (highPriorityCount * 5);
        
        return Math.max(0, score);
    }
    
    @Data
    private static class CodeAnalysisResult {
        private int linesOfCode;
        private boolean hasMainFunction;
        private boolean hasClass;
        private boolean hasNamespace;
        private List<CodeIssue> issues = new ArrayList<>();
    }
    
    @Data
    private static class CodeIssue {
        private String type;
        private String severity; // error, warning, info
        private String message;
        private String suggestion;
        
        public CodeIssue(String type, String severity, String message, String suggestion) {
            this.type = type;
            this.severity = severity;
            this.message = message;
            this.suggestion = suggestion;
        }
    }
    
    @Data
    private static class BestPracticeSuggestion {
        private String title;
        private String description;
        private String suggestion;
        private String example;
        private String priority; // high, medium, low
        private String category;
        
        public BestPracticeSuggestion(String title, String description, 
                                     String suggestion, String example,
                                     String priority, String category) {
            this.title = title;
            this.description = description;
            this.suggestion = suggestion;
            this.example = example;
            this.priority = priority;
            this.category = category;
        }
    }
}

